package stephen.com.dao.base;

import stephen.com.annotation.MyField;
import stephen.com.annotation.Table;
import stephen.com.utils.JDBCUtil;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class BaseDao<T> {


	public void add(T t) {
		Class<?> aClass = t.getClass();
		//第一步 通过反射，拿到注解
		Table table = aClass.getDeclaredAnnotation(Table.class);
		String tableName = null;
		if (null != table) {
			//注解里面的值 就是表名
			tableName = table.value();
		}
		Field[] fields = aClass.getDeclaredFields();
		StringBuilder sql = new StringBuilder();
		sql.append("insert into ").append(tableName).append(" values(");
		for (int i = 1; i <= fields.length; i++) {
			if (i == fields.length) {
				sql.append("?").append(")");
			} else {
				sql.append("?").append(",");
			}
		}


		Connection connection = null;//数据库链接
		PreparedStatement statement = null;//sql预处理执行
		try {
			connection = JDBCUtil.getConnection();
			statement = connection.prepareStatement(sql.toString());
			int index = 1;
			for (Field field : fields) {
				String methodName = "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
				//通过反射 获取get的方法
				Method method = aClass.getDeclaredMethod(methodName);
				//通过反射 代理执行
				Object invoke = method.invoke(t);
				statement.setObject(index, invoke);
				index++;
			}
			statement.execute();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JDBCUtil.close(null, statement, connection);
		}

	}

	public void del(Object id, Class<T> aClass) {
		//第一步 通过反射，拿到注解
		Table table = aClass.getDeclaredAnnotation(Table.class);
		String tableName = null;
		String idName = null;
		if (null != table) {
			//注解里面的值 就是表名
			tableName = table.value();
			idName = table.key();
		}
		String sql = "delete from " + tableName + " where " + idName + " = ?";
		Connection connection = null;
		PreparedStatement statement = null;
		try {
			connection = JDBCUtil.getConnection();
			statement = connection.prepareStatement(sql);
			statement.setObject(1, id);
			statement.execute();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			JDBCUtil.close(null, statement, connection);
		}
	}

	public T get(Object id, Class<T> aClass) {
		//第一步 通过反射，拿到注解
		Table table = aClass.getDeclaredAnnotation(Table.class);
		String tableName = null;
		String idName = null;
		if (null != table) {
			//注解里面的值 就是表名
			tableName = table.value();
			idName = table.key();
		}
		String sql = "select * from " + tableName + " where " + idName + " = ?";
		Connection connection = null;
		PreparedStatement statement = null;
		ResultSet resultSet = null;
		T obj = null;
		try {
			connection = JDBCUtil.getConnection();
			statement = connection.prepareStatement(sql);
			statement.setObject(1, id);
			resultSet = statement.executeQuery();
			if (resultSet.next()) {
				obj = aClass.newInstance();// Student student = new Student();
				//后面都是用反射去获取Student的字段
				Field[] fields = aClass.getDeclaredFields();
				for (Field field : fields) {
					String fieldName = field.getName();
					MyField myField = field.getDeclaredAnnotation(MyField.class);
					if (null != myField) {
						//自定义注解写上列名重新赋值给fieldName
						fieldName = myField.value();
					}
					String methodName = "set" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
					//通过反射 获取set的方法
					Method method = aClass.getDeclaredMethod(methodName, field.getType());
					//通过反射 代理执行 本质上就等同于 student.setXXX(resultSet.getObject("XXX"));
					method.invoke(obj, resultSet.getObject(fieldName));
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JDBCUtil.close(null, statement, connection);
		}
		return obj;
	}

	public void update(T t) {
		String idName = null;
		String idMethodName = null;

		Class<?> aClass = t.getClass();
		//第一步 通过反射，拿到注解
		Table table = aClass.getDeclaredAnnotation(Table.class);
		String tableName = null;
		if (null != table) {
			//注解里面的值 就是表名
			tableName = table.value();
			idName = table.key();
			idMethodName = table.keyName();
		}
		StringBuilder sql = new StringBuilder();
		sql.append("update ").append(tableName).append(" set ").append(idName).append(" = ?,");
		Field[] fields = aClass.getDeclaredFields();
		try {
			for (Field field : fields) {
				String fieldName = field.getName();
				MyField myField = field.getDeclaredAnnotation(MyField.class);
				if (null != myField) {
					//自定义注解写上列名重新赋值给fieldName
					fieldName = myField.value();
				}
				if (!fieldName.equals(idName)) {
					String methodName = "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
					//通过反射 获取get的方法
					Method method = aClass.getDeclaredMethod(methodName);
					Object obj = method.invoke(t);
					if (null != obj) {
						sql.append(fieldName).append(" = ?,");
					}
				}
			}
			sql.delete(sql.lastIndexOf(","), sql.length());
			sql.append(" where ").append(idName).append(" = ? ");
		} catch (Exception e) {
			e.printStackTrace();
		}

		Connection connection = null;
		PreparedStatement statement = null;
		try {
			int count = 0;
			connection = JDBCUtil.getConnection();
			statement = connection.prepareStatement(sql.toString());
			//因为ID 肯定是100%有的，service层会处理
			Method method = aClass.getDeclaredMethod(idMethodName);
			Object id = method.invoke(t);
			statement.setObject(++count, id);
			for (Field field : fields) {
				String fieldName = field.getName();
				MyField myField = field.getDeclaredAnnotation(MyField.class);
				if (null != myField) {
					//自定义注解写上列名重新赋值给fieldName
					fieldName = myField.value();
				}
				if (!fieldName.equals(idName)) {
					String methodName = "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
					//通过反射 获取get的方法
					Method getMethod = aClass.getDeclaredMethod(methodName);
					Object obj = getMethod.invoke(t);
					if (null != obj) {
						statement.setObject(++count, obj);
					}
				}
			}
			statement.setObject(++count, id);
			statement.execute();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JDBCUtil.close(null, statement, connection);
		}

	}
}
